package com.ruiysoft.security.config;

import com.ruiysoft.security.exception.CustomWebResponseExceptionTranslator;
import com.ruiysoft.security.handler.CustomOAuth2AccessDeniedHandler;
import com.ruiysoft.security.point.CustomAuthExceptionEntryPoint;
import com.ruiysoft.security.service.RedisClientDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import javax.annotation.Resource;

/**
 * Created by 化增光 on 2018/10/28.
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Resource
    RedisTokenStore redisTokenStore;

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    TokenGranter tokenGranter;

    @Resource
    RedisClientDetailsService redisClientDetailsService;

    @Resource
    CustomWebResponseExceptionTranslator customWebResponseExceptionTranslator;

    @Resource
    CustomAuthExceptionEntryPoint customAuthExceptionEntryPoint;

    @Resource
    CustomOAuth2AccessDeniedHandler customOAuth2AccessDeniedHandler;

    /**
     * 用来配置令牌端点(Token Endpoint)的安全约束.
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //ingore是完全绕过了spring security的所有filter，相当于不走spring security
        //permitall没有绕过spring security，其中包含了登录的以及匿名的。
        //isAuthenticated 是否已通过身份验证
        //allowFormAuthenticationForClients 开启过滤器认证客户端信息。进行token令牌操作前置
       // security.addTokenEndpointAuthenticationFilter(new EntryGivenEnterpriseFilter());
       // security.addTokenEndpointAuthenticationFilter(new MobileAuthenticationCodeFilter());
        security.authenticationEntryPoint(customAuthExceptionEntryPoint);
        security.accessDeniedHandler(customOAuth2AccessDeniedHandler);
        security
                .allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()");

    }

    /**
     * 用来配置客户端详情服务（ClientDetailsService），客户端详情信息在这里进行初始化
     * @param clients
     * @throws Exception
     */
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(redisClientDetailsService);
    }

    @Bean
    public ApprovalStore approvalStore() {
        TokenApprovalStore approvalStore = new TokenApprovalStore();
        approvalStore.setTokenStore(redisTokenStore);
        return approvalStore;
    }
    /**
     * 用来配置授权（authorization）以及令牌（token）的访问端点和令牌服务(token services)。
     * @param endpoints
     * @throws Exception
     */
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.approvalStore(approvalStore())
                .tokenStore(redisTokenStore)
                .tokenGranter(tokenGranter)
                .authenticationManager(authenticationManager)
                .exceptionTranslator(customWebResponseExceptionTranslator);

    }

    @Bean
    public static NoOpPasswordEncoder passwordEncoder() {
        return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
    }

}
